package com.bfg.controller;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;

/*	This class represents a connection pool. It creates a new connection on demand,
 * 	up to a max number if specified. It is also make sure connection still open 
 * 	before it is returned to the client.
 */
public class DbConnectionPool {

	private String name;
	private String url;
	private String username;
	private String password;
	private int maxConn;

	private int checkedOut;
	private Vector freeConnections = new Vector();

	private PrintWriter log;

	/*
	 * Create new connection pool.
	 * 
	 * @param name The pool name
	 * 
	 * @param url The JDBC URL for database
	 * 
	 * @param username The database username, or null
	 * 
	 * @param password The password username, or null
	 * 
	 * @param maxConn The maximal number of connection, or 0 for no limit
	 */
	public DbConnectionPool(String name, String url, String username,
			String password, int maxConn) {
		this.name = name;
		this.url = url;
		this.username = username;
		this.password = password;
		this.maxConn = maxConn;
	}

	/*
	 * Create a new connection, using username and password if specified
	 */
	private Connection newConnection() {
		Connection conn = null;
		log.println(new Date() + " : "
				+ "Create new connection with URL : " + url);
		try {
			if (username == null)
				conn = DriverManager.getConnection(url);
			else
				conn = DriverManager.getConnection(url, username, password);
		} catch (SQLException e) {
			log.println(new Date() + " : "
					+ "Can't create connection with URL : " + url);
			e.printStackTrace(log);
			return null;
		}
		return conn;
	}

	public synchronized void freeConnection(Connection conn) {
		freeConnections.addElement(conn);
		checkedOut--;
		notifyAll();
	}

	public synchronized Connection getConnection() {
		Connection conn = null;
		if (freeConnections.size() > 0) {
			conn = (Connection) freeConnections.firstElement();
			freeConnections.removeElementAt(0);
			try {
				if (conn.isClosed()) {
					log.println(new Date() + " : " + "Remove bad connection from " + name);
					conn = getConnection();
				}
			} catch (SQLException e) {
				log.println(new Date() + " : " + "Remove bad connection from " + name);
				e.printStackTrace(log);
				conn = getConnection();
			}
		} else if (maxConn == 0 || checkedOut < maxConn) {
			conn = newConnection();
		}
		if (conn != null)
			checkedOut++;
		return conn;
	}

	public synchronized Connection getConnection(long timeout) {
		long startTime = new Date().getTime();
		Connection conn;
		while ((conn = getConnection()) == null) {
			try {
				wait(timeout);
			} catch (InterruptedException e) {
			}
			if ((new Date().getTime() - startTime) >= timeout)
				return null;

		}
		return conn;
	}
	
	public synchronized void release() {
		Enumeration allConnections=freeConnections.elements();
		while(allConnections.hasMoreElements()) {
			Connection conn=(Connection) allConnections.nextElement();
			try {
				conn.close();
				log.println(new Date() + " : " + "Closed connection for pool " + name);
			} catch (SQLException e) {
				log.println(new Date() + " : " + "Can't close connection for pool " + name);
			}
		}
		freeConnections.removeAllElements();
	}
	
	public void settingLogFile(PrintWriter log) {
		this.log=log;
		log.println(new Date() + " : " + "Setting file for logging");
	}
}
